package org.terramagnet.mvcframework.asynchronous.runnable;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 简单异步操作. 直接传入{@link Runnable}对象来进行异步操作。
 *
 * <p>
 * 系统关闭时若存在还未消费的数据会被丢弃！</p>
 *
 * <p>
 * 每一个{@code AsyncRunner}的实例均会产生一个非daemon线程，推荐项目中使用单例模式创建此类，例如：</p>
 * <pre><code>&lt;bean class="org.terramagnet.mvcframework.asynchronous.runnable.AsyncRunner"/&gt;</code></pre>
 *
 * @author lip
 */
public class AsyncRunner {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private final BlockingQueue<Runnable> sharedQueue = new LinkedBlockingQueue<Runnable>();

    private final Thread thread = new Thread(new Runnable() {

        @Override
        public void run() {
            while (true) {
                try {
                    Runnable runnable = sharedQueue.take();
                    runnable.run();
                } catch (InterruptedException ex) {
                    logger.debug("停止线程：{}", thread.getName());
                    break;
                } catch (Exception ex) {
                    logger.error(thread.getName() + "忽略了错误:" + ex.getMessage(), ex);
                }
            }
        }
    });

    /**
     * 当前队列的大小.
     */
    public int size() {
        return sharedQueue.size();
    }

    /**
     * 加入异步操作.
     *
     * @param runnable 具体的异步操作实现类.
     */
    public void put(Runnable runnable) {
        try {
            sharedQueue.put(runnable);
            notifyNewPut();
        } catch (InterruptedException ex) {
            throw new IllegalStateException("加入异步操作出错", ex);
        }
    }

    /**
     * 自定义线程名称.
     *
     * @return 返回"通用异步操作线程".
     */
    protected String getThreadName() {
        return "通用异步操作线程";
    }

    private void notifyNewPut() {
        if (!thread.isAlive()) {
            thread.setDaemon(false);
            thread.setName(getThreadName());
            thread.start();
        }
    }
}
